package com.syh.jn.scm.infrastructure.repository.impl.supplier.finance;

import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.jn.scm.domain.supplier.entity.finance.BusinessAccountRecord;
import com.syh.jn.scm.domain.supplier.entity.logistics.LogisticsBill;
import com.syh.jn.scm.domain.supplier.entity.stock.StockRecord;
import com.syh.jn.scm.domain.supplier.repository.finance.BusinessAccountRecordRepository;
import com.syh.jn.scm.domain.supplier.repository.logistics.LogisticsBillRepository;
import com.syh.jn.scm.domain.supplier.repository.stock.StockRecordRepository;
import com.syh.jn.scm.dto.supplier.finance.BusinessAccountRecordVo;
import com.syh.jn.scm.infrastructure.repository.model.finance.BusinessAccountRecordModel;
import com.syh.jn.scm.infrastructure.repository.model.purchase.PurchaseOrderModel;
import com.syh.jn.scm.infrastructure.repository.model.sale.SaleOrderModel;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import com.syh.jn.scm.service.api.supplier.finance.enums.BusinessAccountRecordEnums;
import com.syh.jn.scm.service.api.supplier.logistics.enums.LogisticsBillEnums;
import org.apache.ibatis.jdbc.SQL;
import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 应收付记录Repository实现
 */
@Repository
public class BusinessAccountRecordRepositoryImpl extends AbstractAggregateRepository<BusinessAccountRecord, BusinessAccountRecordModel, Long> implements BusinessAccountRecordRepository {
    @Override
    protected SQL getViewSql() {

        return new SQL() {{
            SELECT(
                    SQLAliasGenerateUtil.aliasGenerate(BusinessAccountRecordModel.class, "record", null),
                    "CONCAT(IFNULL(downstream.`NAME`, ''), IFNULL(logistics.`NAME`, ''), IFNULL(upstream.`NAME`, '')) AS name"
            );
            FROM("T_FINANCE_BUSINESS_ACCOUNT_RECORD AS record");
            LEFT_OUTER_JOIN("T_BASE_DOWNSTREAM AS downstream ON record.CUSTOMER_ID = downstream.ID AND record.CUSTOMER_TYPE = 1");
            LEFT_OUTER_JOIN("T_BASE_UPSTREAM AS upstream ON record.CUSTOMER_ID = upstream.ID AND record.CUSTOMER_TYPE = 0");
            LEFT_OUTER_JOIN("T_BASE_LOGISTICS AS logistics ON record.CUSTOMER_ID = logistics.ID AND record.CUSTOMER_TYPE = 2");
        }};
    }

    @Override
    protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
        Map<String, String> map = new HashMap<>();
        map.put("id", "record.ID");
        map.put("originalDocumentCode", "record.ORIGINAL_DOCUMENT_CODE");
        map.put("originalDocumentType", "record.ORIGINAL_DOCUMENT_TYPE");
        map.put("customerId", "record.CUSTOMER_ID");
        map.put("customerType", "record.CUSTOMER_TYPE");
        map.put("createTimeStamp", "record.CREATE_TIME_STAMP");
        map.put("recordTimeStamp", "record.RECORD_TIME_STAMP");
        map.put("businessEntityId", "record.BUSINESS_ENTITY_ID");
        map.put("changeAmount", "record.CHANGE_AMOUNT");
        map.put("rePayAmount", "record.RE_PAY_AMOUNT");

        ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
            return map.get(propertyName);
        });
        return parse;
    }

    @Override
    protected Class getViewObject() {
        return BusinessAccountRecordVo.class;
    }

    /**
     * 纠正数据使用 纠正应收付记录中的累计汇总
     *
     * @param customerType 客户类型
     */
    @Override
    public void recalculationAccountRecordSummary(Short customerType) {
        ExtAssert.isTrue(customerType != null, "customerType 不能为 null");

        //获取往来单位列表
        String hql_SelectCustomerIdList = "select model.customerId from BusinessAccountRecordModel model where model.customerType = ? group by model.customerId";
        List<Long> customerIdList = (List<Long>) super.hibernateTemplate.find(hql_SelectCustomerIdList, customerType);
        //依次获取每个往来单位的所有记录
        customerIdList.forEach(customerId -> {
            String hql = "from BusinessAccountRecordModel model where model.customerType = ? and model.customerId = ? order by model.createTimeStamp asc ";
            List<BusinessAccountRecordModel> recordModelList = (List<BusinessAccountRecordModel>) super.hibernateTemplate.find(hql, new Object[]{customerType, customerId});
            BusinessAccountRecordModel beforeBusinessAccountRecordModel = null;
            for (BusinessAccountRecordModel businessAccountRecordModel : recordModelList) {
                if (beforeBusinessAccountRecordModel == null) {
                    businessAccountRecordModel.setSummaryBalance(businessAccountRecordModel.getChangeAmount());
                } else {
                    businessAccountRecordModel.setSummaryBalance(beforeBusinessAccountRecordModel.getSummaryBalance().add(businessAccountRecordModel.getChangeAmount()));
                }
                beforeBusinessAccountRecordModel = businessAccountRecordModel;
            }
        });
    }

    /**
     * 纠正数据使用 纠正应收付记录中的优惠金额
     */
    @Override
    public void recalculationAccountRecordDiscount() {

        String hql_haveDiscountRecordSaleIds =
                "SELECT " +
                        "sale.id " +
                        "FROM " +
                        "SaleOrderModel sale inner join BusinessAccountRecordModel record on sale.id = record.originalDocumentId and record.originalDocumentType = 11 ";

        List<Long> haveDiscountRecordSaleIds = (List<Long>) super.hibernateTemplate.find(hql_haveDiscountRecordSaleIds);
        //获取有优惠金额且没有优惠金额出入库记录的销售订单
        String hql_SelectSaleOrderList =
                "FROM " +
                        "SaleOrderModel sale " +
                        "WHERE " +
                        "sale.discount > 0 ";
        if (haveDiscountRecordSaleIds != null && !haveDiscountRecordSaleIds.isEmpty()) {
            hql_SelectSaleOrderList += "AND sale.id NOT IN (:haveDiscountRecordSaleIds)";
        }
        Query query = super.buildQuery(hql_SelectSaleOrderList);
        if (haveDiscountRecordSaleIds != null && !haveDiscountRecordSaleIds.isEmpty()) {
            query.setParameterList("haveDiscountRecordSaleIds", haveDiscountRecordSaleIds);
        }
        List<SaleOrderModel> sales = query.list();
        sales.forEach(sale -> {
            BusinessAccountRecord record = new BusinessAccountRecord();
            record.setChangeAmount(sale.getDiscount().negate());
            record.setDataType(BusinessAccountRecordEnums.DataType.NORMAL.getStatus());
            record.setCustomerId(sale.getDownStreamCompanyId());
            record.setCustomerType(LogisticsBillEnums.CustomerType.DOWNSTREAM.getStatus());
            record.setBusinessEntityId(sale.getBusinessEntityId());
            record.setOriginalDocumentId(sale.getId());
            record.setOriginalDocumentCode(sale.getCode());
            record.setOriginalDocumentType(BusinessAccountRecordEnums.Type.SALE_DISCOUNT.getStatus());
            record.setCreateTimeStamp(sale.getDeliveryTimestamp());
            this.add(record);
        });

        //获取有优惠金额且没有优惠金额出入库记录的采购订单
        String hql_haveDiscountRecordPurIds =
                "SELECT " +
                        "pur.id " +
                        "FROM " +
                        "PurchaseOrderModel pur inner join BusinessAccountRecordModel record on pur.id = record.originalDocumentId and record.originalDocumentType = 13 ";
        List<Long> haveDiscountRecordPurIds = (List<Long>) super.hibernateTemplate.find(hql_haveDiscountRecordPurIds);
        String hql_SelectPurOrderList =
                "FROM " +
                        "PurchaseOrderModel pur " +
                        "WHERE " +
                        "pur.discount > 0 ";
        if (haveDiscountRecordPurIds != null && !haveDiscountRecordPurIds.isEmpty()) {
            hql_SelectPurOrderList += "AND pur.id NOT IN (:haveDiscountRecordPurIds)";
        }
        query = super.buildQuery(hql_SelectPurOrderList);
        if (haveDiscountRecordPurIds != null && !haveDiscountRecordPurIds.isEmpty()) {
            query.setParameterList("haveDiscountRecordPurIds", haveDiscountRecordPurIds);
        }
        List<PurchaseOrderModel> purs = query.list();
        purs.forEach(pur -> {
            BusinessAccountRecord record = new BusinessAccountRecord();
            record.setChangeAmount(pur.getDiscount().negate());
            record.setDataType(BusinessAccountRecordEnums.DataType.NORMAL.getStatus());
            record.setCustomerId(pur.getUpStreamCompanyId());
            record.setCustomerType(LogisticsBillEnums.CustomerType.UPSTREAM.getStatus());
            record.setBusinessEntityId(pur.getBusinessEntityId());
            record.setOriginalDocumentId(pur.getId());
            record.setOriginalDocumentCode(pur.getCode());
            record.setOriginalDocumentType(BusinessAccountRecordEnums.Type.PUR_DISCOUNT.getStatus());
            record.setCreateTimeStamp(pur.getReceiveTimestamp());
            this.add(record);
        });
    }

    /**
     * 纠正数据使用 纠正订单未生成应收付记录,库存记录
     */
    @Override
    public void correctAccountRecord() {
        //修复应收付记录
        String hql_hasRecordPurOrder = "SELECT " +
                "pur.id " +
                "FROM " +
                "PurchaseOrderModel pur " +
                "INNER JOIN BusinessAccountRecordModel record ON pur.id = record.originalDocumentId " +
                "AND record.originalDocumentType = 5";

        List<Long> hasRecordPurOrderIds = (List<Long>) super.hibernateTemplate.find(hql_hasRecordPurOrder);
        if (hasRecordPurOrderIds != null && !hasRecordPurOrderIds.isEmpty()) {
            String hql_purOrderWithoutRecord = "SELECT logis.id " +
                    "FROM " +
                    "PurchaseOrderModel pur INNER JOIN LogisticsBillModel logis ON pur.id = logis.orderId AND logis.orderType = 2 " +
                    "WHERE pur.id NOT IN (:hasRecordPurOrderIds)";
            Query query = super.buildQuery(hql_purOrderWithoutRecord);
            query.setParameterList("hasRecordPurOrderIds", hasRecordPurOrderIds);
            List<Long> logisIds = query.list();

            logisIds.forEach(id -> {
                LogisticsBillRepository logisRepo = (LogisticsBillRepository) SpringContextUtils.getBean(LogisticsBillRepository.class);
                LogisticsBill bill = logisRepo.getById(id);

                BusinessAccountRecordRepository recordRepo = (BusinessAccountRecordRepository) SpringContextUtils.getBean(BusinessAccountRecordRepository.class);
                BusinessAccountRecord record = new BusinessAccountRecord(bill, BusinessAccountRecordEnums.DataType.NORMAL.getStatus());
                record.setCreateTimeStamp(bill.getReceiveTimestamp());
                recordRepo.add(record);
            });
        }


        //修复库存记录
        String hql_hasStockRecordPurOrder = "SELECT " +
                "pur.id " +
                "FROM " +
                "PurchaseOrderModel pur " +
                "INNER JOIN StockRecordModel record ON pur.id = record.originalOrderId " +
                "AND record.type = 3";

        List<Long> hasStockRecordPurOrderIds = (List<Long>) super.hibernateTemplate.find(hql_hasStockRecordPurOrder);
        if (hasStockRecordPurOrderIds != null && !hasStockRecordPurOrderIds.isEmpty()) {
            String hql_purOrderWithoutRecord = "SELECT logis.id " +
                    "FROM " +
                    "PurchaseOrderModel pur INNER JOIN LogisticsBillModel logis ON pur.id = logis.orderId AND logis.orderType = 2 " +
                    "WHERE pur.id NOT IN (:hasStockRecordPurOrderIds)";
            Query query = super.buildQuery(hql_purOrderWithoutRecord);
            query.setParameterList("hasStockRecordPurOrderIds", hasStockRecordPurOrderIds);
            List<Long> logisIds = query.list();

            logisIds.forEach(id -> {
                LogisticsBillRepository logisRepo = (LogisticsBillRepository) SpringContextUtils.getBean(LogisticsBillRepository.class);
                LogisticsBill bill = logisRepo.getById(id);

                StockRecordRepository stockRecordRepo = (StockRecordRepository) SpringContextUtils.getBean(StockRecordRepository.class);
                StockRecord stockRecord = new StockRecord();
                stockRecord.collect(bill);
                stockRecord.setCreateTimeStamp(bill.getReceiveTimestamp());
                stockRecordRepo.add(stockRecord);
            });
        }


    }

    /**
     * 根据服务商id删除应收付历史记录
     * @param businessEntityId
     */
    @Override
    public void deleteByBusinessEntityId(Long businessEntityId) {
        String hql = "delete from BusinessAccountRecordModel where businessEntityId = :businessEntityId";
        Query query = this.hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(hql);
        query.setParameter("businessEntityId",businessEntityId);
        query.executeUpdate();
    }

}
